﻿using Google.Protobuf.WellKnownTypes;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Threading.Tasks;


namespace SharedKernel.Infrastructure.Caches
{
    /// <summary>
    /// 内存缓存辅助类（支持多数据库隔离）
    /// </summary>
    public class MemoryCacheService : ICacheService
    {
        private readonly IMemoryCache _memoryCache;
        private int _currentDb; // 当前操作的数据库标识（用于隔离不同库的缓存）
        private readonly object _dbLock = new object(); // 用于切换数据库的线程锁

        /// <summary>
        ///  
        /// </summary>
        /// <param name="memoryCache"></param>
        public MemoryCacheService(IMemoryCache memoryCache)
        {
            _memoryCache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache));
            _currentDb = 0; // 默认数据库（可根据需求调整初始值）
        }
        /// <summary>
        /// 是否正常打开
        /// </summary>
        /// <returns></returns>
        public bool IsOpen()
        {
            return _memoryCache != null;
        }

        /// <summary>
        /// 切换当前操作的数据库（线程安全）
        /// </summary>
        /// <param name="db">目标数据库标识</param>
        public void ChangeDataBase(int db)
        {
            lock (_dbLock) // 确保多线程下切换数据库的原子性
            {
                _currentDb = db;
            }
        }

        /// <summary>
        /// 获取缓存项（带数据库隔离）
        /// </summary>
        /// <typeparam name="T">缓存项类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <returns>缓存项（不存在时返回 default(T)）</returns>
        public T? Get<T>(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentException("缓存键不能为空", nameof(key));

            // 构造带数据库前缀的唯一键（格式："数据库ID:原始键"）
            var actualKey = $"{_currentDb}:{key}";
            return _memoryCache.Get<T>(actualKey);
        }

        /// <summary>
        /// 设置缓存项（带数据库隔离和过期时间）
        /// </summary>
        /// <typeparam name="T">缓存项类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存值</param>
        /// <param name="expiration">过期时间（相对当前时间的偏移量）</param>
        /// <returns>是否设置成功（内存缓存无异常时始终返回 true）</returns>
        public bool Set<T>(string key, T value, TimeSpan? expiration = null)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentException("缓存键不能为空", nameof(key));

            var actualKey = $"{_currentDb}:{key}";
            var cacheOptions = new MemoryCacheEntryOptions();

            // 设置过期时间（绝对过期）
            if (expiration.HasValue)
            {
                cacheOptions.AbsoluteExpirationRelativeToNow = expiration;
            }

            // 内存缓存设置（无异常时默认成功）
            var res = _memoryCache.Set(actualKey, value, cacheOptions);
            return !res.Equals(default(T));
        }

        /// <summary>
        /// 删除缓存项 
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>是否删除成功（存在并删除时返回 true）</returns>
        public bool Remove(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentException("缓存键不能为空", nameof(key));

            var actualKey = $"{_currentDb}:{key}";
            _memoryCache.Remove(actualKey);
            return true;
        }

        /// <summary>
        /// 检查缓存项是否存在（带数据库隔离）
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>是否存在</returns>
        public bool Exists(string key)
        {
            if (string.IsNullOrWhiteSpace(key))
                throw new ArgumentException("缓存键不能为空", nameof(key));

            var actualKey = $"{_currentDb}:{key}";
            return _memoryCache.TryGetValue(actualKey, out _);
        }

        /// <summary>
        /// 获取缓存项
        /// </summary>
        /// <typeparam name="T">缓存项类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <returns>缓存项（不存在时返回 default(T)）</returns>
        public async Task<T?> GetAsync<T>(string key)
        {
            return await Task.FromResult(Get<T>(key));
        }

        /// <summary>
        /// 设置缓存项
        /// </summary>
        /// <typeparam name="T">缓存项类型</typeparam>
        /// <param name="key">缓存键</param>
        /// <param name="value">缓存值</param>
        /// <param name="expiration">过期时间（相对当前时间的偏移量）</param>
        /// <returns>是否设置成功（内存缓存无异常时始终返回 true）</returns>
        public async Task<bool> SetAsync<T>(string key, T value, TimeSpan? expiration = null)
        {
            return await Task.FromResult(Set<T>(key, value, expiration));
        }
        /// <summary>
        /// 删除缓存项
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>是否删除成功（存在并删除时返回 true）</returns>
        public async Task<bool> RemoveAsync(string key)
        {
            return await Task.FromResult(Remove(key));
        }

        /// <summary>
        /// 检查缓存项是否存在
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns>是否存在</returns>
        public async Task<bool> ExistsAsync(string key)
        {
            return await Task.FromResult(Exists(key));
        }

    }
}
